
;*******************************************************
;
;	SCSI Driver 'Startup' filter.
;
;	Written by Matt Gulick.		Started July 1,1988
;
;	Copyright Apple Computer, Inc. 1988-90
;
;*******************************************************

;*******************************************************
;
;	This file contains the 'Startup' filter as defined
;	in the ERS.
;
;*******************************************************

;*******************************************************
;
;	Revision History:
;
;*******************************************************
;
;	July 1,		1988	File started.
;	July 21,	1988	reworked logic and added
;						a few new subroutines.
;	April 10,	1989	Started to add code for
;						character devices.

				STRING		PASCAL
				BLANKS		OFF
				PAGESIZE	70
				PRINT		NOGEN
				PRINT		NOMDIR
				MACHINE		M65816

				IMPORT		wake_me_up
				IMPORT		get_mm_id
				IMPORT		get_dvc_ram
				IMPORT		set_512_mode
				IMPORT		select_page_num
				IMPORT		test_unit_rdy
				IMPORT		start_unit
				IMPORT		mode_sense
				IMPORT		read_capacity
				IMPORT		default_dib
				IMPORT		rebld_dibs
				IMPORT		dpi_overide
				IMPORT		set_our_dp
				IMPORT		direct_page
				IMPORT		gsos_dpage
				IMPORT		main_drvr
				IMPORT		internal
				IMPORT		internal_buff
				IMPORT		get_scsimgr
				IMPORT		call_type
				IMPORT		fre_dvc_ram
				IMPORT		dvc_count
				IMPORT		pm_blk_num
				IMPORT		rebuild
				IMPORT		part_num
				IMPORT		do_part_dib
				IMPORT		first_time
				IMPORT		part_cnt
				IMPORT		chk_ram
				IMPORT		dibicise_new_ram
				IMPORT		dibicise_new_dib
				IMPORT		main_caller
				IMPORT		active_starts
				IMPORT		tot_dib_cnt
				IMPORT		t_dvc_blocks

				ENTRY		do_inq_parms
				ENTRY		do_mode_parms
				ENTRY		do_read_cap
				ENTRY		do_partition
				ENTRY		get_nxt_dvc

				PRINT		OFF

				INCLUDE		'scsihd.equates'
				INCLUDE		'M16.MEMORY'
				INCLUDE		'M16.UTIL'
				PRINT		ON

				EJECT
			
;*******************************************************
;
;	Main Entry point to the 'Startup' filter.  This
;	'Filter' is called after the driver is loaded.  The
;	code that follows sets up the drivers environment,
;	then calls 'get_dvc_ram'.  On return from the
;	'get_dvc_ram' call, the following structure are in
;	place if no error ocured.
;
;		dvc_list	=	Long Pointer to device List
;		next_dib	=	Long Pointer to First DIB
;		first_dib	=	Long Pointer to the beginning
;						of the RAM Allocated for the
;						new DIBs.
;
;			This contains enough RAM for one DIB for
;			each device in the device list.  If more
;			space is needed due to partitioning, then
;			the startup filter will be responsible for
;			getting that space from the memory manager.
;
;	From this point, we need to build the DIB for each
;	device. 
;		
;	Inputs:		None.
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	GS/OS Direct Page
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************

				EXPORT	startup
startup			PROC

;-------------------------------------------------------------------------------

				IF		warm_ss_suprt = true		THEN

											;
											; Check to see if this is a WARM STARTUP
											; Call.  If it is, we will need to handle
											; this a lot differently than a normal
											; startup.  First of all our DIBs are, for
											; the most part, already built.  The only
											; possible changes might be in respect to
											; removable media.  In any case we will
											; call the warm start routine in the Driver
											; Mgmt file to take care of this for us.
											;
											; Is it a COLD STARTUP?
											;
				lda		>warm_cold_flag
				and		#$0001
				bne		@do_warm			;It's Warm
@no_warm_start	jmp		@chk_dflt			;It's Cold
											;
											; Check to see if this is for the
											; 'default_dib'.  If it is, then we need
											; to exit with an error.  The error is so
											; that our default DIB is purged from the
											; startup list.
											;
@do_warm		lda		<dib_ptr
				cmp		#default_dib
				bne		@not_dflt

				lda		<dib_ptr+2
				cmp		#^default_dib
				bne		@not_dflt

				lda		#drvr_io			;Error Out.
				sec
				rts
											;
											; Yeah, so it's a WARM STARTUP.  But
											; does this device know what that
											; means?  We'll see!
											;
@not_dflt		ldy		#dib.dvcchar
				lda		[dib_ptr],y
				and		#restartable
				beq		@no_warm_start		;Not restartable.
											;
											; Yeah, so it knows what that means!
											; But first let's see if it is a new
											; DIB.
											;
				ldy		#dib.dvcflag
				lda		[dib_ptr],y
				tax
											;
											; Compare to default value.
											;
				cmp		#wait_mode++\
						cold_dib
				bne		@valid_dib			;Used DIB.  Start it.
											;
											; Zero out the Device Number and
											; remove link.
											;
				lda		#null
				ldy		#dib.devnum
				sta		[dib_ptr],y

				ldy		#dib.dvcchar
				lda		[dib_ptr],y
				and		#linked_dvc--\
						$ffff
				sta		[dib_ptr],y

				lda		#drvr_no_dev		;Error Out.
				sec
				rts
											;
											;
@valid_dib		txa
				and		#cold_dib
				bne		@no_warm_start		;New DIB and Awake.  Do Cold Start
											;
											; Old DIB.  But is it asleep?
											;
				txa
				and		#relaxing
				beq		@over_wake_up		;Not asleep.
											;
											; Call the Warm Restart Routine.
											;
				jsr		wake_me_up
											;
											; The device is now awake.  If it is
											; removable we need to see if the
											; disk has been changed.
											;
@over_wake_up	ldy		#dib.dvcchar
				lda		[dib_ptr],y
				and		#removable
				beq		@bra_been_had		;Not removable.
											;
											; Rebuild the DIBs for this device if
											; this is the first partition for this
											; device.
											;
				ldy		#dib.unitnum
				lda		[dib_ptr],y
				and		#max_p_mask
				bne		@bra_been_had		;Not the head.  They've been done already
											;
											; Current pointer is the first.
											;
				lda		<dib_ptr+2
				ldx		<dib_ptr
@set_pointer	stx		<scsi_zp0
				sta		<scsi_zp0+2
											;
											; Set the Flags.
											;
				ldy		#dib.dvcflag
				lda		[scsi_zp0],y
				and		#dvc_hardofl--\
						$ffff
				ora		#dvc_switch++\
						dvc_online
				sta		[scsi_zp0],y
											;
											; If there is a forward device
											; pointer than get it.
											;
				ldy		#dib.fdvcptr
				lda		[scsi_zp0],y
				tax
				ldy		#dib.fdvcptr+2
				lda		[scsi_zp0],y
				bne		@set_pointer

				jsr		set_512_mode
				lda		#$ffff				;Don't Do Post Driver Installs
				sta		|dpi_overide
				jsr		rebld_dibs			;Rebuild DIBs and Issue a DISK_SW for each
				php
				stz		|dpi_overide		;Clear the Overide
											;
											; Restore the origonal Direct Page values.
											;
				jsr		set_our_dp
				plp
				bcc		@bra_been_had
				jsr		test_unit_rdy
				bcc		@bra_been_had
											;
											; For some reason, we cannot talk to the
											; device.  It must be offline.
											;
@chk_switch		ldy		#dib.dvcflag
				lda		[dib_ptr],y
				and		#dvc_online--\
						$ffff
				sta		[dib_ptr],y

;@bra_been_had	jmp		@links_done
@bra_been_had	bra		@ive_been_had

 				ENDIF

;-------------------------------------------------------------------------------

											;
											; Check to see if this is for the
											; 'default_dib'.  If it is, then we need
											; to build all the devices that we can and
											; exit with an error.  The error is so that
											; our default DIB is purged from the startup
											; list.  The device dispatcher will then
											; call us for the DIB pointed to in the
											; 'default_dib's link pointer.  This and any
											; further 'STARTUP' calls will exit with no
											; error, except that no action will be taken
											; other than to increment the startup call
											; count to be used as a balance for the
											; shutdown calls that will eventually be
											; issued.
											;
@chk_dflt		lda		<dib_ptr
				cmp		#default_dib
				bne		@ive_been_had

				lda		<dib_ptr+2
				cmp		#^default_dib

;-------------------------------------------------------------------------------

				IF			part_suprt = false	Then

				beq		@im_a_virgin

@ive_been_had									;
												; Mark the device as started and
												; as online.
												;
				ldy		#dib.dvcflag
				lda		[dib_ptr],y
				and		#cold_dib--\
						$ffff
				ora		#dvc_online
				sta		[dib_ptr],y

				ELSE

;-------------------------------------------------------------------------------

				bne		@ive_been_had

				jmp		@im_a_virgin

@ive_been_had
												;
												; Clear the Cold Start Flag.
												;
				ldy		#dib.dvcflag
				lda		[dib_ptr],y
				and		#cold_dib--\
						$ffff
				sta		[dib_ptr],y

												;
												; Check the Partition Bits.  If they
												; are all clear, then we will set the
												; head device link to this device.
												;
				ldy		#dib.unitnum
				lda		[dib_ptr],y
				cmp		#$0001
				beq		@jmp_links_done

				and		#max_p_mask
				bne		@not_head
												;
												; Too far to branch to.
												;
@jmp_links_done	jmp		@links_done
												;
												; This is not the first or boot device,
												; nor is it the first or only logical
												; device on this physical device.  That
												; means that it is probably partitioned.
												; This means we need to set the head and
												; forward links.  The following code will
												; do this for us.
												;
												; Get the Device Number for setting as
												; a forward link.  Also save the unit
												; number (less the partition bits) to
												; match the other DIBs from this device.
												;
@not_head		ldy		#dib.devnum
				lda		[dib_ptr],y
				sta		@current_dev

				ldy		#dib.unitnum
				lda		[dib_ptr],y
				and		#max_p_mask\
						--$ffff
				sta		@our_unit

				ldy		#dib.slotnum
				lda		[dib_ptr],y
				sta		@our_slot
												;
												; Start pointer out at the default DIB.
												;
				lda		#default_dib
				sta		<scsi_zp4

				lda		#^default_dib
				sta		<scsi_zp4+2
												;
												; Main Search loop.
												;
												; Advance pointer to the next DIB.  If
												; link is = to zero, then exit loop.
												;
@links_loop		ldy		#dib.linkptr+2
				lda		[scsi_zp4]
				tax
				ora		[scsi_zp4],y
				bne		@non_zero

				jmp		@links_done

@non_zero		lda		[scsi_zp4],y

@advance		sta		<scsi_zp4+2
				stx		<scsi_zp4
												;
												; Check unit number to see if it is the same.
												;
				ldy		#dib.unitnum
				lda		[scsi_zp4],y
				and		#max_p_mask\
						--$ffff
				cmp		@our_unit				;Is it ours?
				bne		@links_loop				;No. Check the next one.
												;
												; Check Slot number to see if it is the same.
												;
				ldy		#dib.slotnum
				lda		[scsi_zp4],y
				cmp		@our_slot				;Is it ours?
				bne		@links_loop				;No. Check the next one.
												;
												; They are equal.  Is the forward link = zero?
												;
				ldy		#dib.fdvclnk
				lda		[scsi_zp4],y
				bne		@links_loop				;No. Check the next one.
												;
												; Yes.  This DIB has no forward device link.
												; We will volunteer the users DIB for the Job.
												; Set the head Link in the DIB called and the
												; forward link in ours.
												;
@found_end		lda		@current_dev
				sta		[scsi_zp4],y

				ldy		#dib.headlnk
				lda		[scsi_zp4],y

				beq		@stuff_head
												;
												; Set Head Pointer to scsi_zp4
												;
				pha

				ldy		#dib.headptr
				lda		[scsi_zp4],y
				sta		[dib_ptr],y
				ldy		#dib.headptr+2
				lda		[scsi_zp4],y
				sta		[dib_ptr],y

				pla
				bra		@do_head
												;
												; Set head Pointer to the same as
												; in scsi_zp4
												;
@stuff_head		ldy		#dib.headptr
				lda		<scsi_zp4
				sta		[dib_ptr],y
				ldy		#dib.headptr+2
				lda		<scsi_zp4+2
				sta		[dib_ptr],y

				ldy		#dib.devnum
				lda		[scsi_zp4],y

@do_head		ldy		#dib.headlnk
				sta		[dib_ptr],y
												;
												; Also set the Forward Device Ptr.
												;
				ldy		#dib.fdvcptr
				lda		<dib_ptr
				sta		[scsi_zp4],y
				ldy		#dib.fdvcptr+2
				lda		<dib_ptr+2
				sta		[scsi_zp4],y
												;
												; And the forward link.
												;
				ldy		#dib.devnum
				lda		[dib_ptr],y

				ldy		#dib.fdvclnk
				sta		[scsi_zp4],y
												;
												; Is it a COLD STARTUP?
												;
				lda		>warm_cold_flag
				and		#$0001
				bne		@links_done				;It's Warm.  Skip the links
												;
												; Set the linked bit in both DIBs.
												;
				ldy		#dib.dvcchar

				lda		[scsi_zp4],y
				ora		#linked_dvc
				sta		[scsi_zp4],y

				lda		[dib_ptr],y
				ora		#linked_dvc
				sta		[dib_ptr],y

				ENDIF

;-------------------------------------------------------------------------------

												;
												; Not the first one, so increment the counter
												; if we are not beyond what we have for an
												; active dib count.
												;
@links_done		lda		|active_starts
				cmp		|tot_dib_cnt
				beq		@over_inc
				inc		|active_starts
@over_inc		clc
				rts
												;
												; Local Data storage here.
												;
@current_dev	dc.w	null					;Device Number for this DIB
@our_unit		dc.w	null					;His unit number less the partition bits.
@our_slot		dc.w	null					;His slot number
												;
												; Check to see if we've been called before.
												; If not then we need to get the gs/os
												; direct page address.
												;
@im_a_virgin	lda		|direct_page
				bne		@we_have_it
												;
												; Where is GS/OS Direct Page?
												;
				tdc
				sta		|gsos_dpage
												;
												; We also need to get the SCSI Managers
												; ID for the S_DISPATCHER.
												;
				jsr		get_scsimgr
				bcs		@rts
												;
												; Get ID from the memory manager.  All that
												; this does is request a new ID.
												;
@we_have_it		jsr		get_mm_id
												;
												; Call the get_dvc_ram subroutine.
												; This will allocate the space
												; that we need for the device list
												; returned by the SCSI Manager.
												; It then calculates a DIB count
												; (Max 256) and allocates RAM for
												; those structures.  This can be
												; increased later if it is needed.
												; This can occur if some of the
												; devices contain more than one
												; partition.
												;
				jsr		get_dvc_ram
				bcc		@do_dflt_dib			;Check for errors.

				jsr		fre_dvc_ram				;Dump Get Devices Ram

				lda		#drvr_no_dev			;Exit
				sec
@rts			rts
												;
												; Now we need to build the DIBs for
												; these devices.  The first one will
												; not be built in the default_dib
												; area.  The default_dib will be 
												; copied first to the new memory that
												; has been allocated.  It is here
												; that the first DIB will be built.
												; After this the last DIB built will
												; be copied into the space for the
												; next DIB to be built and then
												; updated accordingly.  We do not use
												; the default_dib because this will
												; serve to keep this driver active
												; even if no devices are present at
												; boot time.  Just in case a drive
												; does come online later.
												;
@do_dflt_dib	lda		<dvc_list				;Advance pointer to the first entry.
				adc		#$0004					;Pass Direct page pointer and
				sta		<dvc_list				;device count. Carry was CLEAR!!!!
				lda		<dvc_list+2
				adc		#$0000
				sta		<dvc_list+2

				lda		#default_dib
				sta		<last_dib
				lda		#^default_dib
				sta		<last_dib+2

				stz		|main_caller			;tell the link setter that he was called
				clc								;Do Links Also
				jsr		dibicise_new_ram		;by the main loop
				bra		@over

@do_this_dvc	stz		|main_caller			;tell the link setter that he was called
				jsr		dibicise_new_dib		;by the main loop

@over			jsr		do_mode_parms			;Do MODE SENSE supplied parms

				jsr		do_inq_parms			;Do INQUIRY supplied parms

;-------------------------------------------------------------------------------

				IF			block_dvc = true	Then

				jsr		do_read_cap				;Do READ CAPACITY supplied parms

				ENDIF

;-------------------------------------------------------------------------------

				IF			part_suprt = true	Then

				jsr		do_partition			;Do partition DIBs

				ENDIF

;-------------------------------------------------------------------------------

				jsr		get_nxt_dvc				;Go to the next physical device

				bne		@over					;But only if they exist.
												;
												; This SEC is extremely important.  At
												; this point the startup call was issued
												; to the default DIB.  We took this
												; opertunity to build all of our DIBs
												; and we have a count of how many we did
												; build.  We do not want the device manager
												; to keep the default DIB as an active
												; device and so we exit with the carry
												; set.  He will then check the link
												; pointer and if it is not zero, he will
												; call the startup routine for that dib.
												; At that time we will exit with the carry
												; clear.
												;
												; Free Get Devices Ram first.
												;
				jsr		fre_dvc_ram

				lda		#drvr_io
				sec
				rts

				ENDP

				EJECT
			
;*******************************************************
;
;	'do_inq_parms'
;
;	This routine issues an INQUIRY call to the device and
;	then uses the data returned to fill in some of the blank
;	holes in the DIB.
;		
;	Inputs:		<next_dib	=	Next DIB start		(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Outputs:	<next_dib	=	unchanged			(LONG)
;				[next_dib]	=	INQUIRY values set	(PTR)
;									Removable bit
;									Command bitmap
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		None.
;
;*******************************************************

				EXPORT	do_inq_parms
do_inq_parms	PROC
												;
												; Set internal command flag
												;
				dec		|internal
												;
												; Tell the Main Driver where
												; our command structure resides.
												;
				lda		#@start_inq
				sta		<scsi_mdrvr
				lda		#^@start_inq
				sta		<scsi_mdrvr+2
												;
												; And our buffer
												;
				lda		#internal_buff
				sta		<buff_ptr
				lda		#^internal_buff
				sta		<buff_ptr+2
												;
												; And our length 0f $40 Bytes
												;
				lda		#$0040
				sta		<rqst_cnt
				stz		<rqst_cnt+2
												;
												; Stuff the pointer to the dib
												; that we are building into the
												; Direct Page locations.  The
												; main driver will use this to
												; build the SCSI INQUIRY Command
												; that we will issue.
												;
				lda		<next_dib
				sta		<dib_ptr
				lda		<next_dib+2
				sta		<dib_ptr+2
												;
												; Set the Call Type and Issue the
												; INQUIRY Command.
												;
				lda		#scsit_stat
				sta		|call_type
				jsr		|main_drvr
				bcc		@over_0					;Was there an error?

				rts								;Yes.
												;
												; Is the device removable?
												;
@over_0			lda		|inq.removable\
						+internal_buff
				and		#bit_7
				beq		@non_remove
												;
												; Yes.  Set the bit in the
												; characteristics field.
												;
				ldy		#dib.dvcchar
				lda		[next_dib],y
				ora		#removable
				sta		[next_dib],y
				bra		@over_1
												;
												; No.  Clear the bit in the
												; characteristics field.
												;
@non_remove		ldy		#dib.dvcchar
				lda		[next_dib],y
				and		#removable--\
						$ffff
				sta		[next_dib],y
												;
												; Set a ZP pointer to where the
												; command bitmap information will
												; be placed.
												;
@over_1			clc
				lda		<next_dib
				adc		#dib.group0
				sta		<scsi_zp0
				lda		<next_dib+2
				adc		#^dib.group0
				sta		<scsi_zp0+2
												;
												; Not all devices conform to the
												; Apple Command Command Set.  We
												; need to check if the Command
												; Bitmap is available.  If not
												; then we will stuff the default
												; bitmap and then clear bits as
												; the device indicates.  This will
												; be done elsewhere in response to
												; a command not supported error.
												;
												; First check the return length.
												;

				ldy		#dib.trx_len
				lda		[dib_ptr],y
				cmp		#inq.group+5-1			;End of first group - 1
				blt		@do_default
												;
												; We got those bytes. Are they 0?
												;
				short							;5 Bytes to check.  Best done 8 bit

				sec								;The Carry will be our flag
				lda		|inq.group\
						+internal_buff
				bne		@chk_carry				;Must Start w/ Group Zero.

				clc								;The Carry will be our flag
				ldx		#$0005
@chk_bm_loop	lda		|inq.group\
						+internal_buff,x
				bne		@chk_carry
				dex
				bpl		@chk_bm_loop
				sec
@chk_carry		longmx
				bcs		@do_default
												;
												; There are some devices out there
												; that return bogus bitmaps.  They
												; look correct, but are not.  We will
												; check the first 4 bytes of the
												; Bitmap to see if they support the
												; Mandatory Commands.  If not, then
												; we will use our default bitmap.
												;
				lda		|inq.group\
						+internal_buff+1
				and		@min_cmnds
				cmp		@min_cmnds
				bne		@do_default

				lda		|inq.group\
						+internal_buff+3
				and		@min_cmnds+2
				cmp		@min_cmnds+2
				bne		@do_default
												;
												; Zero out the current data in the
												; dib.  If there are any holes in
												; the information then we are sure
												; that those holes are null.
												;
				ldy		#dib.group7\
						-dib.group0\
						+2
				lda		#null
@loop_0			sta		[scsi_zp0],y
				dey
				dey
				bpl		@loop_0
												;
												; Get the group number for the next
												; four bytes of bitmap.
												;
												;	Group x			(BYTE)
												;	Bitmap			(LONG)
												;	Group y			(BYTE)
												;	Bitmap			(LONG)
												;	Group z			(BYTE)
												;	Bitmap			(LONG)
												;	Group '$FF		(BYTE)
												;
				ldx		#null
@loop_1			lda		|inq.group\
						+internal_buff,x

				and		#$00ff					;Real Code
				cmp		#$00ff
				beq		@over_2

				cmp		#$0007+1
				bge		@do_default
												;
												; Convert group number into an
												; index into the group table in
												; the dib.
												;
				asl		a
				asl		a
				tay
				inx
												;
												; Transfer the bitmap.
												;
				lda		|inq.group\
						+internal_buff,x
				sta		[scsi_zp0],y
				inx
				inx
				iny
				iny
				lda		|inq.group\
						+internal_buff,x
				sta		[scsi_zp0],y
				inx
				inx
				bra		@loop_1
												;
												; The device did not support
												; the Command Bitmap in the
												; INQUIRY Parms.  We need to
												; put the default bitmap in
												; place.
												;
@do_default		ldy		#dib.group7\
						-dib.group0\
						+2
@dflt_loop		lda		default_dib\
						+dib.group0,y
				sta		[scsi_zp0],y
				dey
				dey
				bpl		@dflt_loop
												;
												; Clean exit when done.
												;
@over_2			clc
				rts
												;
												; Data Area.
												;
												; Inquiry Command Packet.
												;
@start_inq		dc.b	$12
				dcb.b	11,$00
												;
												; Data of Minimum Command set that
												; must be supported.
												;
@min_cmnds

;-------------------------------------------------------------------------------

				IF			scsi_dtype = direct_acc	Then
												;
												; It is a Direct-Access Device.
												;
				dc.B	$98,$A0,$20,$00			; Group 0 Commands

				ENDIF							;scsi_dtype = direct_acc

;-------------------------------------------------------------------------------

				IF		scsi_dtype = seq_acc	THEN
												;
												; It is a Sequential-Access Device.
												;
				arl								;Cause error if used.  Force definition
				dc.B	$D0,$A0,$20,$00			; Group 0 Commands

				ENDIF							;scsi_dtype = seq_acc

;-------------------------------------------------------------------------------

				IF		scsi_dtype = print_dvc	THEN
												;
												; It is a Printer Device.
												;
				arl								;Cause error if used.  Force definition
				dc.B	$90,$20,$20,$00			; Group 0 Commands

				ENDIF							;scsi_dtype = print_dvc

;-------------------------------------------------------------------------------

				IF		scsi_dtype = proc_dvc	THEN
												;
												; It is a Processor Device.
												;
				arl								;Cause error if used.  Force definition
				dc.B	$98,$A0,$20,$00			; Group 0 Commands

				ENDIF							;scsi_dtype = proc_dvc

;-------------------------------------------------------------------------------

				IF		scsi_dtype = worm_dvc	THEN
												;
												; It is a Write-once Read-multiple Device.
												;
				arl								;Cause error if used.  Force definition
				dc.B	$98,$A0,$20,$00			; Group 0 Commands

				ENDIF							;scsi_dtype = worm_dvc

;-------------------------------------------------------------------------------

				IF		scsi_dtype = read_dacc	THEN
												;
												; It is a Read-only Direct-Access Device.
												;
				dc.B	$90,$00,$23,$00			; Group 0 Commands

				ENDIF							;scsi_dtype = read_dacc

;-------------------------------------------------------------------------------

				IF		scsi_dtype = scanner	THEN
												;
												; It is a Scanner Device.
												;
				dc.B	$90,$00,$23,$00			; Group 0 Commands

				ENDIF							;scsi_dtype = scanner

;-------------------------------------------------------------------------------

				IF		scsi_dtype = optic_mem	THEN
												;
												; It is a Optical Memory Device.
												;
				arl								;Cause error if used.  Force definition
				dc.B	$98,$A0,$20,$00			; Group 0 Commands

				ENDIF							;scsi_dtype = optic_mem

;-------------------------------------------------------------------------------

				IF		scsi_dtype = changer	THEN
												;
												; It is a Changer Device.
												;
				arl								;Cause error if used.  Force definition
				dc.B	$98,$A0,$20,$00			; Group 0 Commands

				ENDIF							;scsi_dtype = changer

;-------------------------------------------------------------------------------

				IF		scsi_dtype = comm_dvc	THEN
												;
												; It is a Communication Device.
												;
				arl								;Cause error if used.  Force definition
				dc.B	$98,$A0,$20,$00			; Group 0 Commands

				ENDIF							;scsi_dtype = comm_dvc

;-------------------------------------------------------------------------------

				IF		scsi_dtype = mcd_40	THEN
												;
												; It is a Direct Access Magnetic
												; Tape Device.
												;
				dc.B	$DF,$77,$FF,$7C			; Group 0 Commands

				ENDIF							;scsi_dtype = mcd_40

;-------------------------------------------------------------------------------

				IF		scsi_dtype = appl_laser	THEN
												;
												; It is an Apple LaserWriter Device.
												;
				arl								;Cause error if used.  Force definition
				dc.B	$98,$A0,$20,$00			; Group 0 Commands

				ENDIF							;scsi_dtype = appl_laser

;-------------------------------------------------------------------------------

				ENDP

				EJECT
			
;*******************************************************
;
;	'do_mode_parms'
;
;	This routine issues an MODE SENSE call to the device and
;	then uses the data returned to fill in some of the blank
;	holes in the DIB.
;		
;	Inputs:		<next_dib	=	Next DIB start		(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Outputs:	<next_dib	=	unchanged			(LONG)
;				[next_dib]	=	MODE SENSE vals set	(PTR)
;									Write Protect bit
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		None.
;
;*******************************************************

				EXPORT	do_mode_parms
do_mode_parms	PROC
												;
												; Stuff the pointer to the dib
												; that we are building into the
												; Direct Page locations.  The
												; main driver will use this to
												; build the SCSI MODE SENSE
												; Command that we will issue.
												;
				lda		<next_dib
				sta		<dib_ptr
				lda		<next_dib+2
				sta		<dib_ptr+2
												;
												; Start the Unit
												;
				jsr		start_unit
												;
												; Check if unit Ready
												;
				jsr		test_unit_rdy
												;
												; Issue MODE SENSE Call
												;
				jsr		mode_sense
				bcs		@rts					;Was there an error?

;-------------------------------------------------------------------------------

				IF		scsi_dtype <> apple_cd\
				AND		scsi_dtype <> scanner	THEN

												;
												; Is the device writable?  If CD-ROM
												; then don't even bother with this
												; code.
												;
				lda		|mode.w_protect\
						+internal_buff
				and		#bit_7
				beq		@over_1					;No.
												;
												; Yes.  Set the bit in the
												; characteristics field.
												;
				ldy		#dib.dvcchar
				lda		#write_allow
				ora		[next_dib],y
				sta		[next_dib],y
		
				ENDIF
		
;-------------------------------------------------------------------------------

@over_1											;Label must always be available.
		
;-------------------------------------------------------------------------------

				IF		scsi_dtype <> mcd_40\
				AND		scsi_dtype <> scanner	THEN
												;
												; Check to see if the device supports
												; the page discriptors.
												;
				lda		|mode.blk_disc\
						+internal_buff
				and		#$00ff
				beq		@clc
												;
												; Ensure that the device is in
												; 512 mode if possible and send
												; data from page 1 back to the
												; device.
												;
				lda		|mode.page_number\
						+internal_buff
				and		#$ff3f					;Clear the invalid bits.
				sta		|select_page_num
				lda		|mode.page_number\
						+internal_buff+2
				ora		#bit_6++\				;Set AWRE and ARRE bits.
						bit_7
				sta		|select_page_num+2
				lda		|mode.page_number\
						+internal_buff+4
				sta		|select_page_num+4
				lda		|mode.page_number\
						+internal_buff+6
				sta		|select_page_num+6

				jsr		set_512_mode
				bcs		@rts

@clc

				ENDIF

;-------------------------------------------------------------------------------

												;
												; Exit
												;
				clc
@rts			rts
												;
												; Data for the MODE SENSE Command
												;
@start_mode		dc.b	$1a
				dc.b	$00
				dc.b	$01
				dcb.b	9,$00

				ENDP

				EJECT
			
;*******************************************************
;
;	'do_read_cap'
;
;	This routine issues an READ CAPACITY call to the
;	device and then uses the data returned to fill in
;	some of the blank holes in the DIB.
;		
;	Inputs:		<next_dib	=	Next DIB start		(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Outputs:	<next_dib	=	unchanged			(LONG)
;				[next_dib]	=	READ CAP.. vals set	(PTR)
;									Block Count
;									Block Size
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		None.
;
;*******************************************************

				EXPORT	do_read_cap
do_read_cap		PROC
		
;-------------------------------------------------------------------------------

				IF		scsi_dtype <> scanner	THEN
												;
												; Stuff the pointer to the dib
												; that we are building into the
												; Direct Page locations.  The
												; main driver will use this to
												; build the SCSI READ CAPACITY
												; Command that we will issue.
												;
				lda		<next_dib
				sta		<dib_ptr
				lda		<next_dib+2
				sta		<dib_ptr+2
												;
												; Issue the READ CAPACITY Command.
												;
				jsr		read_capacity
				bcc		@over_0					;Was there an error?

				rts								;Yes.
												;
												; Get the Block Count (Stored
												; High >> Low.  Must be switched
												; to Low >> High).  This is the last
												; readable block number.  Add 1 to
												; it for comparison reasons.
												;
@over_0			lda		|block.count\
						+internal_buff\
						+2
				xba
				adc		#$0001
				sta		|t_dvc_blocks
				lda		|block.count\
						+internal_buff
				xba
				adc		#null
				sta		|t_dvc_blocks+2

;-------------------------------------------------------------------------------

				IF		block_dvc = true	THEN

				beq		@over_mo
												;
												; Some devices do not return a bitmap
												; of the commands that they support.
												; For these devices we use a default
												; minimum command set.  If the Block
												; Count is > $ffff, then we need to
												; update this to support the extended
												; read and write commands.
												;
				ldy		#dib.group1
				lda		[next_dib],y
				ora		#$b000					;Bit 15 = Extended Read
												;Bit 13 = Extended Write
												;Bit 12 = Extended Seek
				sta		[next_dib],y

@over_mo

				ENDIF

;-------------------------------------------------------------------------------

												;
												; Get the devices block size (This
												; also needs to be switched from
												; High >> Low to Low >> High) and
												; place it in the dib.
												;
				lda		|block.size\
						+internal_buff\
						+2
				xba
				ldy		#dib.blksize
				sta		[next_dib],y
				sta		<blk_size				;Place on direct page.
				lda		|block.size\
						+internal_buff
				xba
				ldy		#dib.blksize+2
				sta		[next_dib],y
				sta		<blk_size+2				;Place on direct page.
												;
												; Clean exit.
												;
				clc
				rts

				ELSE

;-------------------------------------------------------------------------------

				clc
				rts

				ENDIF

;-------------------------------------------------------------------------------

				ENDP

				EJECT
			
;*******************************************************
;
;	'do_partition'
;
;	This routine issues a READ call to the device and
;	then uses the data returned to check for any
;	partitions on the media.
;		
;	Inputs:		<next_dib	=	Next DIB start		(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Outputs:	<next_dib	=	last DIB Built		(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		None.
;
;*******************************************************
												;
												; Start of the code segment for this.
												;
				EXPORT	do_partition
do_partition	PROC

;-------------------------------------------------------------------------------

				IF			part_suprt = true	Then

												;
												; Initialize a few values.
												;
				lda		#$ffff					;The following values will be incrimented
				sta		|first_time				;with zero indication special action.
				sta		|part_num				;This is set to $ffff so that it will only
												;occur on the first pass through.

				stz		|part_cnt
				stz		|pm_blk_num
				stz		|rebuild
												;
												; MAIN LOOP OF CODE SEGMENT.
												;
				jsr		do_part_dib
				rts

				ELSE

;-------------------------------------------------------------------------------

				clc
				rts

				ENDIF

;-------------------------------------------------------------------------------

				ENDP

				EJECT
			
;*******************************************************
;
;	'get_nxt_dvc'
;
;	This routine checks to see if there are any
;	remaining devices in the list handed to us by the
;	GET_DEVICES Call to the SCSI Manager.  If there are
;	devices, then we advance our pointers and exit with
;	the Z flag set.  The caller can the do a BNE to
;	continue his loop ( Z(ero) indicates that there are
;	no devices left ). 
;		
;	Inputs:		<next_dib	=	Next DIB start		(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Outputs:	<next_dib	=	last DIB Built		(LONG)
;				Carry		=	1
;					Acc		=	Error
;				Carry		=	0
;					Acc		=	ram_page_cnt
;							=	0	no more devices
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;								Z=1 if more devices
;								Z=0 if no more devices
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		None.
;
;*******************************************************

				EXPORT	get_nxt_dvc
get_nxt_dvc		PROC
												;
												; Are there any more devices?
												;
				dec		|dvc_count
				bne		@we_have_more
				clc
				rts								;Z Flag set here.
												;
												; Advance the Device Data Pointer
												; in the device list from the SCSI
												; Manager
												;
@we_have_more	clc
				lda		<dvc_list
				adc		#$0004
				sta		<dvc_list
				lda		<dvc_list+2
				adc		#null
				sta		<dvc_list+2
												;
												; Call Check Ram routine.  This will
												; check to see if there is room for an
												; additional DIB.  If not then room
												; will be made for enough DIBs to cover
												; the remaining partitions and devices.
												; From this caller, there should be no
												; partitions to account for.
												;
				stz		|main_caller
				jmp		chk_ram

				ENDP

				END

				EJECT
